package com.czy.workflow.core.context;

import com.czy.workflow.core.annotation.TaskAfterMethod;
import com.czy.workflow.core.exception.FlowException;
import com.czy.workflow.core.model.FlowResult;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/***
 * @ClassName: FlowAspect
 * @Description: TODO
 * @author：libi
 * @date： 2020/3/10 12:02
 * @version： V1.0.0
 * @CopyRight：czy
 */
@Aspect
@Component
public class FlowAspect {

    @Autowired
    FlowContext flowContext;


    @AfterReturning(pointcut = "@annotation(com.czy.workflow.core.annotation.TaskAfterMethod)", returning = "rvt")
    public Object after(JoinPoint joinPoint, Object rvt) throws Throwable {
        if(rvt instanceof FlowResult){
            FlowResult flowResult = (FlowResult) rvt;
            if(flowResult.isSuccess()){
                handleFlow(joinPoint);
            }
        }
        return rvt;
    }


    private boolean handleFlow(JoinPoint joinPoint) throws FlowException {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        TaskAfterMethod taskAfterMethod = methodSignature.getMethod().getAnnotation(TaskAfterMethod.class);
        List<String> parameterNames = Arrays.asList(methodSignature.getParameterNames());
        int i = parameterNames.indexOf(taskAfterMethod.taskIdAlias());
        int j = parameterNames.indexOf(taskAfterMethod.nodeIdAlias());
        int k = parameterNames.indexOf(taskAfterMethod.optionAlias());
        if(i >= 0 && j >= 0 && k >= 0){
            String taskId = (String) joinPoint.getArgs()[i];
            String nodeId = (String) joinPoint.getArgs()[j];
            String option = (String) joinPoint.getArgs()[k];

            return flowContext.getTaskExecutor().execute(taskId, nodeId, option);
        }

        return false;
    }


}
